/*
 * Copyright (c) 2025 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "appfreeze_cpu_freq_manager.h"

#include <fcntl.h>
#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdint>
#include <dlfcn.h>
#include <cstdio>

#include "file_ex.h"
#include "directory_ex.h"
#include "string_ex.h"
#include "hilog_tag_wrapper.h"
#include "time_util.h"
#include "appfreeze_util.h"
#include "dfx_define.h"
#include "fault_data.h"

namespace OHOS {
namespace AppExecFwk {
namespace {
    constexpr int64_t HZ_TO_MHZ = 1000;
    constexpr size_t CPU_FREQ_AND_TIME_NUM = 5;
    constexpr int CPU_FREQ_DECIMAL_BASE = 10;
    constexpr float CPU_PERCENTAGE = 100.0f;
    constexpr uint32_t TIME_IN_STATE_FIRST_INDEX = 0;
    constexpr uint32_t TIME_IN_STATE_SECOND_INDEX = 1;
    constexpr uint32_t START_TIME_FIRST_INDEX = 13;
    constexpr uint32_t START_TIME_SECOND_INDEX = 14;
    constexpr const char* const LOG_FILE_HEAD = "Generated by HiviewDFX @OpenHarmony";
    constexpr const char* const LOG_FILE_SEP = "===============================================================";
    constexpr const char* const LIB_THREAD_CPU_LOAD_PATH = "libucollection_utility.z.so";
    constexpr int TIME_LIMIT = 6000; // 6s
    constexpr size_t MAX_CPU_MAP_SIZE = 10;
    constexpr uint32_t DEFAULT_CPU_SIZE = 1;
    constexpr const char* const CPU_INFO_PREFIX = "cpu-info-";

}
std::shared_ptr<AppfreezeCpuFreqManager> AppfreezeCpuFreqManager::instance_ = nullptr;
ffrt::mutex AppfreezeCpuFreqManager::freezeInfoMutex_;
int AppfreezeCpuFreqManager::cpuCount_ = 0;
std::map<std::string, CpuDataProcessor> AppfreezeCpuFreqManager::cpuInfoMap_;

typedef double (*GetThreadCpuload)(int);

AppfreezeCpuFreqManager::AppfreezeCpuFreqManager()
{
    cpuCount_ = AppfreezeUtil::GetCpuCount();
}

AppfreezeCpuFreqManager::~AppfreezeCpuFreqManager()
{
}

AppfreezeCpuFreqManager &AppfreezeCpuFreqManager::GetInstance()
{
    static AppfreezeCpuFreqManager instance;
    return instance;
}

void AppfreezeCpuFreqManager::ClearOldCpuData(uint64_t curTime)
{
    std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
    if (cpuInfoMap_.size() < MAX_CPU_MAP_SIZE) {
        return ;
    }
    for (auto it = cpuInfoMap_.begin(); it != cpuInfoMap_.end();) {
        auto diff = curTime - it->second.GetCpuStartTime().halfStartTime;
        if (diff > TIME_LIMIT || diff < 0) {
            it = cpuInfoMap_.erase(it);
        } else {
            ++it;
        }
    }
}

bool AppfreezeCpuFreqManager::IsSkipTask(uint64_t curTime, const std::string &key, int32_t pid)
{
    std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
    auto it = cpuInfoMap_.find(key);
    if (it != cpuInfoMap_.end()) {
        auto diff = curTime - it->second.GetCpuStartTime().halfStartTime;
        if (diff > TIME_LIMIT || diff < 0) {
            it = cpuInfoMap_.erase(it);
        } else {
            TAG_LOGW(AAFwkTag::APPDFR, "Skip this task. "
                "The task of the current process is already being executed, pid:%{public}d", pid);
            return true;
        }
    }
    if (cpuInfoMap_.size() >= MAX_CPU_MAP_SIZE) {
        TAG_LOGW(AAFwkTag::APPDFR, "Skip this task. "
            "The current queue can only execute up to %{public}zu tasks", MAX_CPU_MAP_SIZE);
        return true;
    }
    return false;
}

bool AppfreezeCpuFreqManager::InitCpuDataProcessor(const std::string &eventType,
    int32_t pid, int32_t uid, const std::string &stackPath)
{
    uint64_t curTime = AppfreezeUtil::GetMilliseconds();
    ClearOldCpuData(curTime);
    std::string key = eventType + std::to_string(uid);
    if (IsSkipTask(curTime, key, pid)) {
        return false;
    }
    CpuStartTime cpuStartTime = {
        .halfStartTime = curTime,
        .optimalCpuStartTime = GetOptimalCpuTime(pid),
    };
    std::vector<std::vector<CpuFreqData>> cpuData;
    std::vector<TotalTime> totalTimeList;
    ParseCpuData(cpuData, totalTimeList);
    CpuDataProcessor data(cpuData, totalTimeList, cpuStartTime, stackPath, pid);
    {
        std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
        cpuInfoMap_[key] = data;
    }
    TAG_LOGD(AAFwkTag::APPDFR, "init success. eventType: %{public}s path: %{public}s "
        "halfStartTime: %{public}" PRIu64", optimalCpuStartTime: %{public}" PRIu64".",
        eventType.c_str(), stackPath.c_str(), cpuStartTime.halfStartTime,
        cpuStartTime.optimalCpuStartTime);
    return true;
}

void AppfreezeCpuFreqManager::ParseCpuData(std::vector<std::vector<CpuFreqData>>& datas,
    std::vector<TotalTime>& totalTimeLists)
{
    TAG_LOGD(AAFwkTag::APPDFR, "ParseCpuData start time: %{public}s",
        AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
    std::string tmp = "start time: " + AbilityRuntime::TimeUtil::DefaultCurrentTimeStr();
    TAG_LOGW(AAFwkTag::APPDFR, "ParseCpuData called, %{public}s", tmp.c_str());
    for (int32_t i = 0; i < cpuCount_; ++i) {
        std::vector<CpuFreqData> parseDatas;
        TotalTime totalTime{};
        if (ReadCpuDataByNum(i, parseDatas, totalTime)) {
            datas.push_back(parseDatas);
            totalTimeLists.push_back(totalTime);
        }
    }
    TAG_LOGD(AAFwkTag::APPDFR, "ParseCpuData end time: %{public}s",
        AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
}

bool AppfreezeCpuFreqManager::ReadCpuDataByNum(int32_t num, std::vector<CpuFreqData>& parseDatas,
    TotalTime& totalTime)
{
    TAG_LOGD(AAFwkTag::APPDFR, "ReadCpuDataByNum start time: %{public}s",
        AbilityRuntime::TimeUtil::DefaultCurrentTimeStr().c_str());
    if (num > cpuCount_) {
        TAG_LOGE(AAFwkTag::APPDFR, "Read cpu info failed, num:%{public}d, cpuCount:%{public}d",
            num, cpuCount_);
        return false;
    }
    std::string cpuFreqPath = "/sys/devices/system/cpu/cpu" + std::to_string(num) + "/power/time_in_state";
    std::string data;
    if (!LoadStringFromFile(cpuFreqPath, data)) {
        TAG_LOGE(AAFwkTag::APPDFR, "Read cpu time failed, cpuFreqPath:%{public}s", cpuFreqPath.c_str());
        return false;
    }
    std::istringstream iss(data);
    std::string line;
    while (std::getline(iss, line)) {
        if (line.empty()) {
            continue;
        }
        std::vector<std::string> tokens;
        SplitStr(line, " ", tokens);
        if (tokens.size() != CPU_FREQ_AND_TIME_NUM) {
            continue;
        }
        CpuFreqData cpuFreqData{};
        cpuFreqData.frequency = static_cast<uint64_t>(strtoull(tokens[TIME_IN_STATE_FIRST_INDEX].c_str(),
            nullptr, CPU_FREQ_DECIMAL_BASE));
        cpuFreqData.runningTime = static_cast<uint64_t>(strtoull(tokens[TIME_IN_STATE_SECOND_INDEX].c_str(),
            nullptr, CPU_FREQ_DECIMAL_BASE));
        totalTime.totalRunningTime += cpuFreqData.runningTime;
        for (size_t i = 1; i < tokens.size(); ++i) {
            totalTime.totalCpuTime += static_cast<uint64_t>(strtoull(tokens[i].c_str(), nullptr,
                CPU_FREQ_DECIMAL_BASE));
        }
        parseDatas.push_back(cpuFreqData);
    }
    return true;
}

std::string AppfreezeCpuFreqManager::GetCpuStr(int code, std::vector<FrequencyPair>& freqPairs,
    float percentage)
{
    std::sort(freqPairs.begin(), freqPairs.end(),
        [] (const auto& pairOne, const auto& pairTwo) { return pairOne.percentage > pairTwo.percentage; });

    std::stringstream ss;
    ss << "cpu" << std::to_string(code) << " Usage " << AppfreezeUtil::RoundToTwoDecimals(percentage) << "%, ";
    bool isEnd = true;
    for (const auto& pair : freqPairs) {
        if (!isEnd) {
            ss << ", ";
        }
        isEnd = false;
        ss << pair.frequency << "MHZ " << AppfreezeUtil::RoundToTwoDecimals(pair.percentage) << "%";
    }
    ss << std::endl;
    return ss.str();
}

bool AppfreezeCpuFreqManager::GetCpuTotalValue(size_t i, std::vector<TotalTime> totalTimeList,
    std::vector<TotalTime> blockTotalTimeList, TotalTime& totalTime)
{
    if (totalTimeList.size() <= i || totalTimeList.size() != blockTotalTimeList.size()) {
        TAG_LOGE(AAFwkTag::APPDFR, "index:%{public}zu, halfTotal size:%{public}zu, "
            "blockTotal size:%{public}zu.", i, totalTimeList.size(), blockTotalTimeList.size());
        return false;
    }
    totalTime.totalCpuTime = totalTimeList[i].totalCpuTime > blockTotalTimeList[i].totalCpuTime ?
        (totalTimeList[i].totalCpuTime - blockTotalTimeList[i].totalCpuTime) :
        (blockTotalTimeList[i].totalCpuTime - totalTimeList[i].totalCpuTime);
    if (totalTime.totalCpuTime <= 0) {
        TAG_LOGE(AAFwkTag::APPDFR, "totalCpuTime:%{public}" PRIu64"less than zero.", totalTime.totalCpuTime);
        return false;
    }
    totalTime.totalRunningTime = totalTimeList[i].totalRunningTime > blockTotalTimeList[i].totalRunningTime ?
        (totalTimeList[i].totalRunningTime - blockTotalTimeList[i].totalRunningTime) :
        (blockTotalTimeList[i].totalRunningTime - totalTimeList[i].totalRunningTime);
    return true;
}

std::string AppfreezeCpuFreqManager::GetCpuInfoContent(
    const std::vector<std::vector<CpuFreqData>> &handlingHalfCpuData, const std::vector<TotalTime> &totalTimeList)
{
    if (handlingHalfCpuData.size() == 0 || totalTimeList.size() == 0) {
        return "";
    }
    std::stringstream ss;
    ss << "start time:" << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
    std::vector<std::vector<CpuFreqData>> blockCpuData;
    std::vector<TotalTime> blockTotalTimeList;
    ParseCpuData(blockCpuData, blockTotalTimeList);
    if (handlingHalfCpuData.size() != blockCpuData.size()) {
        TAG_LOGE(AAFwkTag::APPDFR, "Half and block have different sizes, halfData:%{public}zu, "
            "blockData:%{public}zu", handlingHalfCpuData.size(), blockCpuData.size());
        return "";
    }
    for (size_t i = 0; i < handlingHalfCpuData.size(); ++i) {
        auto halfData = handlingHalfCpuData[i];
        auto blockData = blockCpuData[i];
        if (halfData.size() != blockData.size()) {
            TAG_LOGE(AAFwkTag::APPDFR, "Half and block have different sizes, halfData:%{public}zu, "
                "blockData:%{public}zu", halfData.size(), blockData.size());
            return "";
        }
        TotalTime totalTime{};
        if (!GetCpuTotalValue(i, totalTimeList, blockTotalTimeList, totalTime)) {
            return "";
        }
        float percentage = (static_cast<float>(totalTime.totalRunningTime) /
            static_cast<float>(totalTime.totalCpuTime)) * CPU_PERCENTAGE;;
        std::vector<FrequencyPair> freqPairs;
        for (size_t j = 0; j < halfData.size(); ++j) {
            FrequencyPair pair{};
            uint64_t runningTime = halfData[j].runningTime > blockData[j].runningTime ?
                (halfData[j].runningTime - blockData[j].runningTime) :
                (blockData[j].runningTime - halfData[j].runningTime);
            pair.percentage = (static_cast<float>(runningTime) /
                static_cast<float>(totalTime.totalCpuTime)) * CPU_PERCENTAGE;
            if (pair.percentage < 1 || halfData[j].frequency != blockData[j].frequency) {
                continue;
            }
            pair.frequency = halfData[j].frequency / HZ_TO_MHZ;
            freqPairs.push_back(pair);
        }
        ss << GetCpuStr(i, freqPairs, percentage);
    }
    ss << "end time:" << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
    return ss.str();
}

uint64_t AppfreezeCpuFreqManager::GetAppCpuTime(int32_t pid)
{
    if (pid < 0) {
        return 0;
    }
    uint64_t cpuTime = 0;
    std::string filePath = "/proc/" + std::to_string(pid) + "/task/" + std::to_string(pid) + "/stat";
    std::string content;
    if (!LoadStringFromFile(filePath, content)) {
        TAG_LOGE(AAFwkTag::APPDFR, "Read cpu task stat failed, path:%{public}s", filePath.c_str());
        return cpuTime;
    }
    if (!content.empty()) {
        std::vector<std::string> tokens;
        SplitStr(content, " ", tokens);
        if (tokens.size() <= START_TIME_SECOND_INDEX) {
            TAG_LOGE(AAFwkTag::APPDFR, "GetAppCpuTime failed, content size: %{public}zu.", tokens.size());
            return cpuTime;
        }
        cpuTime = static_cast<uint64_t>(strtoull(tokens[START_TIME_FIRST_INDEX].c_str(),
            nullptr, CPU_FREQ_DECIMAL_BASE));
        cpuTime += static_cast<uint64_t>(strtoull(tokens[START_TIME_SECOND_INDEX].c_str(),
            nullptr, CPU_FREQ_DECIMAL_BASE));
    }
    return cpuTime;
}

uint64_t AppfreezeCpuFreqManager::GetProcessCpuTime(int32_t pid)
{
    if (pid < 0) {
        return 0;
    }
    std::string statPath = "/proc/" + std::to_string(pid) + "/stat";
    std::string content;
    if (!LoadStringFromFile(statPath, content)) {
        TAG_LOGE(AAFwkTag::APPDFR, "Read cpu stat failed, path:%{public}s", statPath.c_str());
        return 0;
    }
    uint64_t processCpuTime = 0;
    if (!content.empty()) {
        std::vector<std::string> tokens;
        SplitStr(content, " ", tokens);
        if (tokens.size() <= START_TIME_SECOND_INDEX) {
            TAG_LOGE(AAFwkTag::APPDFR, "GetAppCpuTime failed, content size: %{public}zu.", tokens.size());
            return processCpuTime;
        }
        processCpuTime = static_cast<uint64_t>(strtoull(tokens[START_TIME_FIRST_INDEX].c_str(),
            nullptr, CPU_FREQ_DECIMAL_BASE));
        processCpuTime += static_cast<uint64_t>(strtoull(tokens[START_TIME_SECOND_INDEX].c_str(),
            nullptr, CPU_FREQ_DECIMAL_BASE));
    }
    return processCpuTime;
}

uint64_t AppfreezeCpuFreqManager::GetDeviceRuntime()
{
    std::string statPath = AppfreezeUtil::PROC_STAT_PATH;
    std::string content;
    if (!LoadStringFromFile(statPath, content)) {
        TAG_LOGE(AAFwkTag::APPDFR, "Read device run time failed, path:%{public}s", statPath.c_str());
        return 0;
    }
    uint64_t deviceRuntime = 0;
    std::string line;
    std::istringstream iss(content);
    if (std::getline(iss, line) && !line.empty()) {
        std::vector<std::string> strings;
        SplitStr(line, " ", strings);
        if (strings.size() <= DEFAULT_CPU_SIZE) {
            TAG_LOGE(AAFwkTag::APPDFR, "GetDeviceRuntime failed, string size: %{public}zu.", strings.size());
            return deviceRuntime;
        }
        for (size_t i = 1; i < strings.size(); ++i) {
            deviceRuntime += static_cast<uint64_t>(strtoull(strings[i].c_str(), nullptr,
                CPU_FREQ_DECIMAL_BASE));
        }
    }
    return deviceRuntime;
}

double AppfreezeCpuFreqManager::GetOptimalCpuTime(int32_t pid)
{
    int maxCpuCount = cpuCount_ - AppfreezeUtil::CPU_COUNT_SUBTRACT;
    if (maxCpuCount <= 0) {
        TAG_LOGE(AAFwkTag::APPDFR, "GetOptimalCpuTime failed, maxCpuCount:%{public}d", maxCpuCount);
        return -1;
    }
    std::string statPath = "/sys/devices/system/cpu/cpu" + std::to_string(maxCpuCount) + "/cpu_capacity";
    std::string content;
    int ret = -1;
    if (!LoadStringFromFile(statPath, content)) {
        TAG_LOGE(AAFwkTag::APPDFR, "GetOptimalCpuTime failed, path:%{public}s, errno:%{public}d",
            statPath.c_str(), errno);
        return ret;
    }
    if (content.empty()) {
        TAG_LOGE(AAFwkTag::APPDFR, "Read info failed, path:%{public}s", statPath.c_str());
        return ret;
    }
    int32_t dmips = static_cast<int32_t>(strtoull(content.c_str(), nullptr, CPU_FREQ_DECIMAL_BASE));
    void* threadFuncHandler = dlopen(LIB_THREAD_CPU_LOAD_PATH, RTLD_LAZY);
    if (threadFuncHandler == nullptr) {
        TAG_LOGE(AAFwkTag::APPDFR, "dlopen failed, funcHandler is nullptr.");
        return ret;
    }
    dlerror();
    char* err = nullptr;
    auto getThreadCpuload = reinterpret_cast<GetThreadCpuload>(dlsym(threadFuncHandler, "GetThreadCpuload"));
    err = dlerror();
    if (err != nullptr) {
        TAG_LOGE(AAFwkTag::APPDFR, "dlsym GetThreadCpuload func failed. %{public}s", err);
        return ret;
    }
    double optimalCpuTime = getThreadCpuload(pid);
    threadFuncHandler = nullptr;
    getThreadCpuload = nullptr;
    dlclose(threadFuncHandler);
    if (dmips <= 0 || optimalCpuTime < 0) {
        return ret;
    }
    TAG_LOGW(AAFwkTag::APPDFR, "dmips %{public}d optimalCpuTime %{public}lf", dmips, optimalCpuTime);
    return optimalCpuTime / dmips;
}

std::string AppfreezeCpuFreqManager::GetStartTime(uint64_t start)
{
    const uint32_t placeholder = 3;
    uint64_t startTime = start / AppfreezeUtil::SEC_TO_MILLISEC;
    std::ostringstream startTimeStr;
    startTimeStr << AppfreezeUtil::TimestampFormatToDate(startTime, "%Y-%m-%d %H:%M:%S");
    startTimeStr << ":" << std::setw(placeholder) << std::setfill('0') <<
        std::to_string(start % AppfreezeUtil::SEC_TO_MILLISEC);
    return startTimeStr.str();
}

std::string AppfreezeCpuFreqManager::GetStaticInfoHead()
{
    std::ostringstream staticInfoStr;
    staticInfoStr << "#Basic Concepts" << std::endl;
    staticInfoStr << "T1:  StaticsDuration, EndTime - StartTime." << std::endl;
    staticInfoStr << "T2:  CpuTime              --Time that spend on CPU." << std::endl;
    staticInfoStr << "T3:  SyncWaitTime         --SleepingTime + Runnable Time, etc." << std::endl;
    staticInfoStr << "T4:  OptimalCpuTime       --run the thread at the max Core's max cpu capacity." << std::endl;
    staticInfoStr << "T5:  SupplyAvailableTime  --T2 - T3. Time can be optimized by scheduling." << std::endl;
    staticInfoStr << "Equation:  T1 = T2 + T3. T2 = T4 = T5." << std::endl;
    staticInfoStr <<
        "|-----------------------------------StaticsDuration-----------------------------------|." << std::endl;
    staticInfoStr <<
        "|-------------------------CpuTime----------------------|--------SyncWaitTime----------|." << std::endl;
    staticInfoStr <<
        "|----OptimalCpuTime----|------SupplyAvailableTime------|--------SyncWaitTime----------|." << std::endl;
    return staticInfoStr.str();
}

std::string AppfreezeCpuFreqManager::GetStaticInfo(int32_t pid, CpuStartTime cpuStartTime)
{
    std::ostringstream staticInfoStr;
    staticInfoStr << GetStaticInfoHead() << std::endl;
    staticInfoStr << "#Basic Statistical Infomation " << std::endl;
    staticInfoStr << "ProcessCpuTime: " << GetProcessCpuTime(pid) << " ms" << std::endl;
    staticInfoStr << "DeviceRuntime: " << GetDeviceRuntime() << " ms" << std::endl;
    staticInfoStr << "Tid: " << pid << std::endl;
    staticInfoStr << "StartTime: " << GetStartTime(cpuStartTime.halfStartTime) << std::endl;
    staticInfoStr << "EndTime: " << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
    uint64_t duration = AppfreezeUtil::GetMilliseconds() - cpuStartTime.halfStartTime;
    staticInfoStr << "StaticsDuration: " << duration << " ms" << std::endl;
    uint64_t cpuTime = GetAppCpuTime(pid);
    uint64_t syncWaitTime = duration - cpuTime;
    uint64_t optimalCpuTime = GetOptimalCpuTime(pid) - cpuStartTime.optimalCpuStartTime;
    uint64_t supplyAvailableTime = duration - optimalCpuTime - syncWaitTime;
    staticInfoStr << "CpuTime: " << cpuTime << " ms" << std::endl;
    staticInfoStr << "SyncWaitTime: " << syncWaitTime << " ms" << std::endl;
    staticInfoStr << "OptimalCpuTime: " << optimalCpuTime << " ms" << std::endl;
    staticInfoStr << "SupplyAvailableTime: " << supplyAvailableTime << " ms" << std::endl;
    return staticInfoStr.str();
}

void AppfreezeCpuFreqManager::WriteDfxLogToFile(const std::string &filePath, const std::string &bundleName)
{
    std::stringstream ss;
    ss << LOG_FILE_HEAD << std::endl;
    ss << LOG_FILE_SEP << std::endl;
    ss << "TimeStamp: " << AbilityRuntime::TimeUtil::DefaultCurrentTimeStr() << std::endl;
    ss << "Module name: " << bundleName << std::endl;
    OHOS::SaveStringToFile(filePath, ss.str());
}

bool AppfreezeCpuFreqManager::IsContainHalfData(const std::string &key, CpuDataProcessor &cpuData, int32_t pid)
{
    std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
    auto it = cpuInfoMap_.find(key);
    if (it == cpuInfoMap_.end()) {
        TAG_LOGI(AAFwkTag::APPDFR, "Not find warning fault, pid: %{public}d", pid);
        return false;
    }
    int warningPid = it->second.GetPid();
    if (warningPid != pid) {
        TAG_LOGI(AAFwkTag::APPDFR, "Not find current pid:%{public}d, warning pid:%{public}d", pid, warningPid);
        return false;
    }
    auto diff = AppfreezeUtil::GetMilliseconds() - it->second.GetCpuStartTime().halfStartTime;
    if (diff > TIME_LIMIT) {
        it = cpuInfoMap_.erase(it);
        TAG_LOGI(AAFwkTag::APPDFR, "The last fault occurred more than 6 seconds ago, "
            "diff: %{public}" PRIu64", pid: %{public}d.", diff, pid);
        return false;
    }
    cpuData = it->second;
    return true;
}

std::string AppfreezeCpuFreqManager::WriteCpuInfoToFile(const std::string &eventType,
    const std::string &bundleName, int32_t uid, int32_t pid, const std::string &eventName)
{
    std::string key = eventType + std::to_string(uid);
    CpuDataProcessor cpuData;
    if (!IsContainHalfData(key, cpuData, pid)) {
        return "";
    }

    std::string cpuInfo = GetCpuInfoContent(cpuData.GetHandlingHalfCpuData(), cpuData.GetTotalTimeList());
    if (cpuInfo.empty()) {
        return "";
    }
    std::string fileName = CPU_INFO_PREFIX + std::to_string(uid) +
        AbilityRuntime::TimeUtil::FormatTime("%Y%m%d%H%M%S");
    std::string filePath = AppfreezeUtil::CreateFile(AppfreezeUtil::EVENTLOG_PATH, fileName);
    WriteDfxLogToFile(filePath, bundleName);

    std::ostringstream str;
    str << std::endl << GetStaticInfo(pid, cpuData.GetCpuStartTime());
    str << std::endl << "#CpuFreq Usage (usage >=1%)" << std::endl << cpuInfo << std::endl;
    std::string path = filePath + "," + cpuData.GetStackPath();
    OHOS::SaveStringToFile(filePath, str.str(), false);
    {
        std::lock_guard<ffrt::mutex> lock(freezeInfoMutex_);
        cpuInfoMap_.erase(key);
    }
    TAG_LOGW(AAFwkTag::APPDFR, "Write CpuInfo to file: %{public}s", path.c_str());
    return path;
}
}  // namespace AppExecFwk
}  // namespace OHOS
